<template>
  <div>
    <h1 class="row">按↑↓←→操作</h1>
    <div v-for="(row,x) in list" :key="x" class="row">
      <div v-for="(item,y) in row" :key="y" class="item">
        <div :class="['box',boxClass(item)]">{{item===0?'':item}}</div>
      </div>
    </div>
    <div class="row">
      <button @click="startGame(currentMode)">开始新的游戏</button>
      <button @click="startGame(4)">4x4</button>
      <button @click="startGame(5)">5x5</button>
    </div>
  </div>
</template>
<script>
export default {
  created() {
    this.initialization();
    document.addEventListener("keyup", this.keyboard);
  },
  name: "App",
  components: {},
  data() {
    return {
      list: null,
      currentMode: 4
    };
  },
  methods: {
    // 开始游戏
    startGame(e) {
      this.currentMode = e;
      this.initialization();
      this.random();
    },
    // 初始化游戏
    initialization() {
      let arr1 = new Array(this.currentMode);
      arr1 = Array.from(arr1, () => {
        return 0;
      });
      let arr2 = Array.from([...arr1], () => {
        return [...arr1];
      });
      this.list = arr2;
    },
    // 生成随机数
    random() {
      // 生产随机数函数
      const created = a => {
        return Math.floor(Math.random() * a) + 1;
      };
      // a是选出剩下有几个0
      let a = 0;
      this.list.forEach(row => {
        row.forEach(item => {
          if (item === 0) {
            a++;
          }
        });
      });
      if (a === 0) return;
      // b是剩下的0中的随机的第几个
      let b = created(a);
      let c = 0;
      this.list.some(row => {
        return row.some((item, index) => {
          if (item === 0) {
            c++;
          }
          if (c === b) {
            if (Math.random() > 0.1) {
              row[index] = 2;
            } else {
              row[index] = 4;
            }
          }
          return c === b;
        });
      });
      if (a === 1) {
        setTimeout(this.gameOver, 0);
      }
    },
    // 监听键盘事件
    keyboard(e) {
      let array;
      let isMove = false;
      switch (e.keyCode) {
        case 37: {
          const [arr, result] = this.left();
          if (result) {
            array = arr;
            isMove = true;
          }
          break;
        }
        case 38: {
          const [arr, result] = this.top();
          if (result) {
            array = arr;
            isMove = true;
          }
          break;
        }
        case 39: {
          const [arr, result] = this.right();
          if (result) {
            array = arr;
            isMove = true;
          }
          break;
        }
        case 40: {
          const [arr, result] = this.bottom();
          if (result) {
            array = arr;
            isMove = true;
          }
          break;
        }
      }
      if (isMove) {
        this.list = array;
        setTimeout(this.random, 200);
      }
    },
    // 复制函数
    copy(a) {
      let b;
      switch (typeof a) {
        case "object":
          if (a instanceof Array) {
            let arr1 = [];
            a.forEach(item => {
              arr1.push(this.copy(item));
            });
            b = arr1;
          } else {
            let obj = {};
            Object.keys(a).forEach(item => {
              obj[item] = this.copy(a[item]);
            });
            b = obj;
          }
          break;
        default:
          b = a;
          break;
      }
      return b;
    },
    // 上事件
    top() {
      let arr = this.copy(this.list);
      let result = false;
      const move = () => {
        for (let i = 0; i < this.currentMode; i++) {
          const arr2 = [arr[0][i], arr[1][i], arr[2][i], arr[3][i]];
          const a = [];
          if (this.currentMode === 5) {
            arr2.push(arr[4][i]);
          }
          for (let i = 1; i < this.currentMode; i++) {
            if (arr2[i] !== 0) {
              for (let j = 0; j < i; j++) {
                if (arr2[j] === 0) {
                  arr2[j] = arr2[i];
                  arr2[i] = 0;
                  result = true;
                } else if (
                  ((arr2[j] === arr2[i] && arr2[j + 1] === 0 && j + 1 !== i) ||
                    (arr2[j] === arr2[i] && j + 1 === i)) &&
                  !a.some(item => {
                    return item === j;
                  })
                ) {
                  a.push(j);
                  arr2[j] = 2 * arr2[i];
                  arr2[i] = 0;
                  result = true;
                  break;
                }
              }
            }
          }
          arr2.forEach((item, index) => {
            arr[index][i] = item;
          });
        }
      };
      move();
      return [arr, result];
    },
    // 左事件
    left() {
      let arr = this.copy(this.list);
      let result = false;
      const move = () => {
        arr.forEach((row, x) => {
          const arr2 = [...row];
          const a = [];
          for (let i = 1; i < this.currentMode; i++) {
            if (arr2[i] !== 0) {
              for (let j = 0; j < i; j++) {
                if (arr2[j] === 0) {
                  arr2[j] = arr2[i];
                  arr2[i] = 0;
                  result = true;
                  break;
                } else if (
                  ((arr2[j] === arr2[i] && arr2[j + 1] === 0 && j + 1 !== i) ||
                    (arr2[j] === arr2[i] && j + 1 === i)) &&
                  !a.some(item => {
                    return item === j;
                  })
                ) {
                  a.push(j);
                  arr2[j] = 2 * arr2[i];
                  arr2[i] = 0;
                  result = true;
                  break;
                }
              }
            }
          }
          arr[x] = arr2;
        });
      };
      move();
      return [arr, result];
    },
    // 右事件
    right() {
      let arr = this.copy(this.list);
      let result = false;
      const move = () => {
        arr.forEach((row, x) => {
          const arr2 = [...row];
          const a = [];
          for (let i = this.currentMode - 2; i >= 0; i--) {
            if (arr2[i] !== 0) {
              for (let j = this.currentMode - 1; j > i; j--) {
                if (arr2[j] === 0) {
                  arr2[j] = arr2[i];
                  arr2[i] = 0;
                  result = true;
                } else if (
                  ((arr2[j] === arr2[i] && arr2[j - 1] === 0 && j - 1 !== i) ||
                    (arr2[j] === arr2[i] && j - 1 === i)) &&
                  !a.some(item => {
                    return item === j;
                  })
                ) {
                  a.push(j);
                  arr2[j] = 2 * arr2[i];
                  arr2[i] = 0;
                  result = true;
                  break;
                }
              }
            }
          }
          arr[x] = arr2;
        });
      };
      move();
      return [arr, result];
    },
    // 下事件
    bottom() {
      let arr = this.copy(this.list);
      let result = false;
      const move = () => {
        for (let i = 0; i < this.currentMode; i++) {
          const arr2 = [arr[0][i], arr[1][i], arr[2][i], arr[3][i]];
          const a = [];
          if (this.currentMode === 5) {
            arr2.push(arr[4][i]);
          }
          for (let i = this.currentMode - 2; i >= 0; i--) {
            if (arr2[i] !== 0) {
              for (let j = this.currentMode - 1; j > i; j--) {
                if (arr2[j] === 0) {
                  arr2[j] = arr2[i];
                  arr2[i] = 0;
                  result = true;
                } else if (
                  ((arr2[j] === arr2[i] && arr2[j - 1] === 0 && j - 1 !== i) ||
                    (arr2[j] === arr2[i] && j - 1 === i)) &&
                  !a.some(item => {
                    return item === j;
                  })
                ) {
                  a.push(j);
                  arr2[j] = 2 * arr2[i];
                  arr2[i] = 0;
                  result = true;
                  break;
                }
              }
            }
          }
          arr2.forEach((item, index) => {
            arr[index][i] = item;
          });
        }
      };
      move();
      return [arr, result];
    },
    // 游戏结束的判定条件
    gameOver() {
      const [a1, r1] = this.left();
      const [a2, r2] = this.top();
      const [a3, r3] = this.right();
      const [a4, r4] = this.bottom();
      console.log(a1, a2, a3, a4);
      if (r1 || r2 || r3 || r4) return;
      else alert("gameOver");
    },
    // 类名
    boxClass(e) {
      return "box" + e;
    }
  }
};
</script>

<style>
.row {
  display: flex;
  justify-content: center;
}
.item {
  height: 40px;
  width: 40px;
  background: #bbada0;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
.box {
  height: 35px;
  width: 35px;
  line-height: 35px;
  text-align: center;
  border-radius: 3px;
  background: #ccc0b2;
}
.box2 {
  background: #eee4da;
  color: #7a6d65;
}
.box4 {
  background: #ebdcbd;
  color: #7a6d65;
}
.box8 {
  background: #f2b179;
  color: #ffffff;
}
.box16 {
  background: #f7925c;
  color: #ffffff;
}
.box32 {
  background: #f57656;
  color: #ffffff;
}
.box64 {
  background: #f4522c;
  color: #ffffff;
}
.box128 {
  background: #edce71;
  color: #ffffff;
}
.box256 {
  background: #ff3030;
  color: #ffffff;
}
.box512 {
  background: #4385ff;
  color: #ffffff;
}
.box1024 {
  background: #67e99d;
  color: #ffffff;
  font-size: 12px;
}
.box2048 {
  background: #ff3030;
  color: #ffffff;
  font-size: 12px;
}
button {
  margin: 20px 20px;
  height: 30px;
  border-radius: 15px;
  background: rgb(112, 205, 218);
  color: #ffffff;
  border: none;
  cursor: pointer;
}
</style>
